-- @Author: baidwwy
-- @Date:   2018-04-10 22:51:52
-- @Last Modified by:   baidwwy
-- @Last Modified time: 2018-08-11 16:25:08

assert(引擎, "引擎未启动。")
local __Vector = require("gge_Vector")()
local GGELUA = class()

local _eq       = function (a,b) return a.x==b.x and a.y==b.y end-- (==)
local _lt       = function (a,b) return a.x<b.x and a.y<b.y end-- (<)
local _le       = function (a,b) return a.x<=b.x and a.y<=b.y end-- (<=)
local _add      = function (a,b)-- (+)
    if type(a)=='table' and type(b)=='table' then
        a.x = a.x or a[1];a.y = a.y or a[2]
        b.x = b.x or b[1];b.y = b.y or b[2]
        return GGELUA(a.x + b.x,a.y + b.y)
    elseif type(a) =='number'then
        return GGELUA(a + b.x,a + b.y)
    elseif type(b) =='number'then
        return GGELUA(a.x + b,a.y + b)
    end
end
local _sub      = function (a,b)-- (-)
    if type(a)=='table' and type(b)=='table' then
        a.x = a.x or a[1];a.y = a.y or a[2]
        b.x = b.x or b[1];b.y = b.y or b[2]
        return GGELUA(a.x - b.x,a.y - b.y)
    elseif type(a) =='number'then
        return GGELUA(a - b.x,a - b.y)
    elseif type(b) =='number'then
        return GGELUA(a.x - b,a.y - b)
    end
end

local _mul      = function (a,b)-- (*)
    if type(a)=='table' and type(b)=='table' then
        a.x = a.x or a[1];a.y = a.y or a[2]
        b.x = b.x or b[1];b.y = b.y or b[2]
        return GGELUA(a.x * b.x,a.y * b.y)
    elseif type(a) =='number'then
        return GGELUA(a * b.x,a * b.y)
    elseif type(b) =='number'then
        return GGELUA(a.x * b,a.y * b)
    end
end

local _div      = function (a,b)-- (/)
    if type(a)=='table' and type(b)=='table' then
        a.x = a.x or a[1];a.y = a.y or a[2]
        b.x = b.x or b[1];b.y = b.y or b[2]
        return GGELUA(a.x / b.x,a.y / b.y)
    elseif type(a) =='number'then
        return GGELUA(a / b.x,a / b.y)
    elseif type(b) =='number'then
        return GGELUA(a.x / b,a.y / b)
    end
end

local _tostring = function (a,b) return string.format("%d\t%d",a.x,a.y) end
function GGELUA:初始化(x,y)
    self.x = tonumber(x) or 0
    self.y = tonumber(y) or 0

    local mt = getmetatable(self)
        mt.__eq       = _eq
        mt.__lt       = _lt
        mt.__le       = _le
        mt.__add      = _add
        mt.__sub      = _sub
        mt.__mul      = _mul
        mt.__div      = _div
        mt.__tostring = _tostring
end
function GGELUA:ceil()
    self.x = math.ceil(self.x)
    self.y = math.ceil(self.y)
    return self
end
function GGELUA:floor()
    self.x = math.floor(self.x)
    self.y = math.floor(self.y)
    return self
end
function GGELUA:unpack()
    return self.x,self.y
end
function GGELUA:更新(x,y)
    self.x = y and x or x.x or x[1]
    self.y = y and y or x.y or x[2]
    return self
end
function GGELUA:复制()
    return GGELUA(self.x,self.y)
end
function GGELUA:随机(x,x1,y,y1)
    self.x = math.random(x, x1)
    self.y = math.random(y, y1)
    return self
end
--取两点距离
function GGELUA:取距离(x,y)
    if type(x) == 'table' then
        x,y=x.x or 0,x.y or 0
    end
    return math.sqrt(math.pow(self.x-x,2) + math.pow(self.y-y,2))
end
--取两点弧度
function GGELUA:取弧度(_x,_y)
    local x,y = self.x,self.y
    if type(_x) == 'table' then
        _x,_y=_x.x or 0,_x.y or 0
    end
    if(_y ==y and _x==x)then
        return 0
    elseif(_y >=y and _x<=x)then
        return math.pi-math.abs(math.atan((_y-y)/(_x-x)))
    elseif(_y <=y and _x>=x)then
        return math.pi2-math.abs(math.atan((_y-y)/(_x-x)))
    elseif(_y <=y and _x<=x)then
        return math.atan((_y-y)/(_x-x))+math.pi
    elseif(_y >=y and _x>=x)then
        return math.atan((_y-y)/(_x-x))
    end
end
function GGELUA:取角度(x,y)--math.rad
    return math.deg(self:取弧度(x,y))
end
function GGELUA:取地图位置(w,h)--图块宽高
    return GGELUA(math.ceil(self.x/w), math.ceil(self.y/h))
end
function GGELUA:取距离坐标(r,a) --距离,弧度
    local x,y = 0,0
    x=r* math.cos(a)+self.x
    y=r* math.sin(a)+self.y
    return GGELUA(x,y)
end
function GGELUA:取移动坐标(r,x,y)--距离,目标点
    local a = self:取弧度 (x,y)
    return self:取距离坐标(r,a)
end
function GGELUA:移动(r,x,y)--距离,目标点
    local a = self:取弧度 (x,y)
    self.x = r* math.cos(a)+self.x
    self.y = r* math.sin(a)+self.y
    return self
end
function GGELUA:取屏幕坐标(w,h) --地图宽高
    local rx,ry = 0,0
    local x,y = self.x,self.y
    if w >引擎.宽度 then
        if (x>引擎.宽度2 and x<w-引擎.宽度2) then
            rx = -(x-引擎.宽度2)
        elseif x<=引擎.宽度2 then
            rx=0
        elseif x>=w-引擎.宽度2 then
            rx=-(w-引擎.宽度)
        end
    end
    if h > 引擎.高度 then
        if (y>引擎.高度2 and y<h-引擎.高度2) then
            ry = -(y-引擎.高度2)
        elseif y<=引擎.高度2 then
            ry=0
        elseif y>=h-引擎.高度2 then
            ry=-(h-引擎.高度)
        end
    end
    return GGELUA(rx,ry)
end

function GGELUA:画线(x,y,color)
    if type(x) == 'table' then
        color = y
        x,y=x.x or 0,x.y or 0
    end
    color = color or 0xFFFF0000
    引擎.画线(self.x,self.y,x,y,color)
    return self
end
function GGELUA:画圆(...)
    self:显示(...)
end
function GGELUA:画矩形(_x,_y,color)
    if type(_x) == 'table' then
        color = _y
        _x,_y=_x.x or 0,_x.y or 0
    end
    color = color or 0xFFFF0000
    local x,y = self.x,self.y
    引擎.画线(x,y,_x,y,color)--上
    引擎.画线(x,_y,_x,_y,color)--下
    引擎.画线(x,y,x,_y,color)--左
    引擎.画线(_x,y,_x,_y,color)--右
end
--@参数 半径,边数,颜色
function GGELUA:显示(color,r,num)
    r = r or 3
    num = num or 20
    color = color or 0xFFFF0000
    local a = 360/num
    local pxy,pxy1
    local draw = 引擎.画线
    for i=0,num-1 do
        pxy = self:取距离坐标(r,math.rad(i*a))--rad角度转弧度
        pxy1 = self:取距离坐标(r,math.rad((i+1)*a))
        draw(pxy.x,pxy.y,pxy1.x,pxy1.y,color)
    end
    return self
end

--======================================================================
-- @brief 获得两矢量点积
-- @param v 矢量
-- @return 两矢量点积
function GGELUA:Dot(x,y)
    if type(x) == 'table' then
        x,y=x.x or 0,x.y or 0
    end
    return x*self.x+y*self.y
end
--标准化矢量
function GGELUA:Normalize()
    local n = self:Length()
    if n<2e-37 then return end
    n=1.0/n
    self.x = self.x*n
    self.y = self.y*n
    return self
end
-- @brief 获得矢量长度
-- @return 矢量长度
function GGELUA:Length()
    return math.sqrt(self:LengthSquared())
end
-- @brief 获得矢量长度的平方
-- @return 矢量长度的平方
function GGELUA:LengthSquared()
    return self.x^2+self.y^2
end
-- @brief 返回与X轴的角度
-- @return 返回与X轴的角度
function GGELUA:Angle()
    return math.atan2(self.y,self.x)
end
-- @brief 获得两矢量间角度
-- @param v 矢量
-- @return 两矢量间角度
function GGELUA:AngleTo(x,y)
    if type(x) == 'table' then
        x,y=x.x or 0,x.y or 0
    end
    -- self:Normalize()
    -- x:Normalize()
    -- return math.acos(self:Dot(x))
    return __Vector:AngleTo(self.x,self.y,x,y)
end
-- @brief 如果v在该矢量的顺时针方向返回1，如果在逆时针方向返回-1，否则返回0
-- @param v 矢量
-- @return 如果v在该矢量的顺时针方向返回1，如果在逆时针方向返回-1，否则返回0
function GGELUA:Sign(x,y)
    if type(x) == 'table' then
        x,y=x.x or 0,x.y or 0
    end
    return __Vector:Sign(self.x,self.y,x,y)
end
-- @brief 返回与该矢量垂直的矢量
-- @return 返回与该矢量垂直的矢量
function GGELUA:Perpendicular()
    return GGELUA(-self.y,self.x)
    --return GGELUA(__Vector:Perpendicular(self.x,self.y))
end
-- @brief 返回以v为平面的反射矢量，v必须是标准化矢量
-- @return 返回以v为平面的反射矢量
function GGELUA:Reflect(x,y)
    if type(x) == 'table' then
        x,y=x.x or 0,x.y or 0
    end
    return GGELUA(__Vector:Reflect(self.x,self.y,x,y))
end
-- @brief 设置成以v为平面的反射矢量，v必须是标准化矢量
-- @return 返回该矢量
function GGELUA:ToReflect(x,y)
    if type(x) == 'table' then
        x,y=x.x or 0,x.y or 0
    end
    return GGELUA(__Vector:ToReflect(self.x,self.y,x,y))
end
-- @brief 将矢量旋转指定角度
-- @param radian 旋转角度
function GGELUA:Rotate(radian)
    local cosAngle = math.cos(radian)
    local sinAngle = math.sin(radian)
    local x,y = self.x,self.y
    self.x = x * cosAngle - y * sinAngle
    self.y = x * sinAngle + y * cosAngle
    return self
end
-- @brief 使矢量长度不超过指定的长度
-- @param max 最大长度
function GGELUA:Clamp(max)
    if self:Length()<max  then return end
    self:Normalize()
    self.x = self.x*max
    self.y = self.y*max
    return self
end
return GGELUA